package ae.pcfc.cldos.online.web.services.security.provider;

import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.rememberme.InvalidCookieException;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.util.Assert;

import ae.pcfc.cldos.online.common.delegate.EncryptionDelegate;
import ae.pcfc.cldos.online.web.services.security.MyTokenBasedRememberMeService;
import ae.pcfc.cldos.online.web.util.RequestUtils;

/**
 * 
 * 
 * @author arosa
 *
 */
public class MyTokenBasedRememberMeServiceImpl extends TokenBasedRememberMeServices implements MyTokenBasedRememberMeService {
	
	private static final String DEFAULT_PASSWORD_COOKIE_NAME = "psc";
	
	private String passwordCookieName = DEFAULT_PASSWORD_COOKIE_NAME;
	
	public void setPasswordCookieName(String passwordCookieName) {
		this.passwordCookieName = passwordCookieName;
	}
	
	private EncryptionDelegate encryptionDelegate;
	
	public void setEncryptionDelegate(EncryptionDelegate encryptionDelegate) {
		this.encryptionDelegate = encryptionDelegate;
	}
	
	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.hasLength(getKey());
    }
	
	@Override
	public void onLoginSuccess(HttpServletRequest request,
			HttpServletResponse response,
			Authentication successfulAuthentication) {
		
		String password = (String)successfulAuthentication.getCredentials();
		
		String encryptedPassword = encryptionDelegate.encryptAndEncode(password);
		
		Cookie passwordCookie = new Cookie(passwordCookieName, encryptedPassword);
		passwordCookie.setMaxAge(getTokenValiditySeconds());
		response.addCookie(passwordCookie);
		
		super.onLoginSuccess(request, response, successfulAuthentication);
	}
	
	@Override
	protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request,
            HttpServletResponse response) {

        if (cookieTokens.length != 3) {
            throw new InvalidCookieException("Cookie token did not contain 3" +
                    " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
        }

        long tokenExpiryTime;

        try {
            tokenExpiryTime = new Long(cookieTokens[1]).longValue();
        }
        catch (NumberFormatException nfe) {
            throw new InvalidCookieException("Cookie token[1] did not contain a valid number (contained '" +
                    cookieTokens[1] + "')");
        }

        if (isTokenExpired(tokenExpiryTime)) {
            throw new InvalidCookieException("Cookie token[1] has expired (expired on '"
                    + new Date(tokenExpiryTime) + "'; current time is '" + new Date() + "')");
        }

        String password = getPasswordFromPasswordCookie(request);
        
        @SuppressWarnings("unchecked")
		UserDetails userDetails = new User(cookieTokens[0], password, true, 
        		true, true, true, (List<GrantedAuthority>)Collections.EMPTY_LIST); 

        return userDetails;
    }
	
	/**
	 * 
	 * Overriden creation of succesfull authentificetion
	 */
	protected Authentication createSuccessfulAuthentication(HttpServletRequest request, UserDetails user) {
		UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user.getUsername(), 
				user.getPassword());
        return auth;
    }

	/**
	 * Overriden cookie cancelation for delete our password cookie
	 * 
	 */
	@Override
	protected void cancelCookie(HttpServletRequest request,
			HttpServletResponse response) {
		
		Cookie passwordCookie = new Cookie(passwordCookieName, "");
		passwordCookie.setMaxAge(0);
		response.addCookie(passwordCookie);
		String contextPath = request.getContextPath();
		passwordCookie.setPath(contextPath.length() > 0 ? contextPath : "/");
		
		super.cancelCookie(request, response);
	}
	
	/**
	 * Get password from encrypted cookie
	 * 
	 * @param request
	 * @return
	 */
	private String getPasswordFromPasswordCookie(HttpServletRequest request){
		String result = "";
		String cookieValue = RequestUtils.getCookieValueByCookieName(passwordCookieName, request);
		if(cookieValue!=null){
			result = encryptionDelegate.decodeAndDecrypt(cookieValue);
		}
		return result;
	}

}
